/*                                    _
 *   ___ _ __ ___ _ __ ___   ___   __| |
 *  / __| '__/ __| '_ ` _ \ / _ \ / _` |
 *  \__ \ |  \__ \ | | | | | (_) | (_| |
 *  |___/_|  |___/_| |_| |_|\___/ \__,_|                                  
 *
 *     _    _ .   _  _  . _  _| _   
 *    _\|_||\/|\/(_)|   || |(_|(/_><
 *
 *     __|_ _ _|_ _   |_  _ | _  _  _
 *    _\ | (_| | (/_  | |(/_||_)(/_| 
 *                          |       
 ******************************************
 ******************************************
 ******************************************
 *  _    |_ |. _   |`    _  __|_. _  _  _
 * |_)|_||_)||(_  ~|~|_|| |(_ | |(_)| |_\
 * |                                     
 *		// Forces the survivor index to rebuild instantly
 *		SurvivorIndex_Rebuild()
 *
 *		// Iterate over each alive survivor from the index
 *		FOR_EACH_SURVIVOR_FROM_INDEX(`survivor var`) `loop body`
 *
 ******************************************
 ******************************************
 ******************************************
 * . _ _  _ | _  _ _  _  _ _|_ _ _|_. _  _ 
 * || | ||_)|(/_| | |(/_| | | (_| | |(_)| |
 *       |                                 
 *		This keeps a up-to-date array of just the Alive Survivors,
 *		so it is possible to quickly iterate it without doing any checks
 *		like IsClientInGame, GetClientTeam, IsPlayerAlive, etc.
 *
 *		The SurvivorIndex automatically updates itself when an event 
 *		occurs that would cause the index to be invalidated such as a player
 *		disconnecting, changing teams, or becoming dead.
 *
 *		When writing code in performance-critical code like
 *		OnGameFrame it is best to avoid looping 1 through MaxClients
 *		since in a typical situation (1-18) there will only be 4
 *		alive survivors and most of the loop iterations wil be redundant.
 *
 *		In other sections of the code it is preferrable to use the standard
 *		FOR_EACH macros available in srs.helpers\macros.sp
 */

static const Float:	REBUILD_DELAY	= 0.3;

//leave this as accessible to other files since we want to access it directly via the FOR_EACH macro
new survivorCount					= 0;
new survivorIndex[MAXPLAYERS+1]		= 0;

//Use this to iterate over the SurvivorIndex
//Its similar to FOR_EACH_ALIVE_SURVIVOR, except less costly in OnGameFrame Situations
#define FOR_EACH_ALIVE_SURVIVOR_INDEXED(%1)									\
	for(new %1 = 0, _surv_idx = 1; _surv_idx <= survivorCount; _surv_idx++)	\
		if(((%1 = survivorIndex[_surv_idx])) && IsValidEntity(%1) || true)							
		

SurvivorIndex_OnPluginStart()
{
	_SI_HookEvents();
}

SurvivorIndex_OnMapStart()
{
	survivorCount = 0;
}

SurvivorIndex_OnMapEnd()
{
	survivorCount = 0;
}

_SI_HookEvents()
{
	// these hooks do nothing but keeping the Survivor Index up to date
	HookEvent("round_start", 		_SI_Event_TempStop_Event, 	EventHookMode_PostNoCopy);
	HookEvent("round_end", 			_SI_Event_TempStop_Event, 	EventHookMode_PostNoCopy);
	HookEvent("player_team", 		_SI_Event_TempStop_Event, 	EventHookMode_PostNoCopy);
	HookEvent("player_spawn", 		_SI_Event, 					EventHookMode_PostNoCopy);
	HookEvent("player_disconnect", 	_SI_Event, 					EventHookMode_PostNoCopy);
	HookEvent("player_death", 		_SI_Event, 					EventHookMode_PostNoCopy);
	HookEvent("player_bot_replace", _SI_Event, 					EventHookMode_PostNoCopy);
	HookEvent("bot_player_replace", _SI_Event, 					EventHookMode_PostNoCopy);
}

public _SI_Event_TempStop_Event(Handle:event, const String:name[], bool:dontBroadcast)
{
	survivorCount = 0;	// to get rid of GetEntProp Entity errors before and after Mapchange
	CreateTimer(REBUILD_DELAY, _SI_RebuildIndex_Timer);
}

public Action:_SI_RebuildIndex_Timer(Handle:timer)
{
	SurvivorIndex_Rebuild();
}

public _SI_Event(Handle:event, const String:name[], bool:dontBroadcast)
{
	SurvivorIndex_Rebuild();
}

SurvivorIndex_Rebuild()
{
	survivorCount = 0;
	if (!IsServerProcessing()) return;

	FOR_EACH_ALIVE_SURVIVOR(i)
	{
		survivorCount++;
		survivorIndex[survivorCount] = i;
	}
}
